/** * Java Diagram Package; An extremely flexible and fast multipurpose diagram component for Swing. Copyright (C) 2001 Eric Crahen <crahen@cse.buffalo.edu> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package diagram.tool; import java.awt.Cursor; import java.awt.Point; import java.awt.event.MouseEvent; import java.awt.geom.Point2D; import javax.swing.SwingUtilities; import javax.swing.event.MouseInputAdapter; import diagram.Diagram; import diagram.DiagramUI; import diagram.Figure; import diagram.figures.PolyLink; /** * @class LinkShapping * * @date 08-20-2001 * @author Eric Crahen * @version 1.0 * * This tool allows PolyLink figures to be dragged or edited. Left-clicking and * dragging allows new points to be inserted into the PolyLink, or existing points * to be moved. Right-clicking allows existing points to be deleted. The two end * points are immune to these operations. */ public class LinkShappingTool extends AbstractTool { // Margin of error for clicking on a line, and for detecting a drag public static final double CLICK_TOLERANCE = 6.0; public static final double DRAG_TOLERANCE = 6.0; // Drag cursor private static final Cursor HD_CURSOR = new Cursor(Cursor.HAND_CURSOR); // Orginal diagram cursor private Cursor originalCursor = null; // Diagram private Diagram diagram; // Mouse dragged from private Point2D dragPoint; // Link getting shapped private PolyLink polyLink; // Point first pressed private Point2D pressPoint; private MouseHandler mouseHandler = new MouseHandler(); /** * Install the support in the specified Diagram * * @param Diagram */ public void install(Diagram diagram) { if(diagram.getSelectionModel() == null) throw new RuntimeException("LinkShapping requires SelectionModel support"); diagram.addMouseListener(mouseHandler); diagram.addMouseMotionListener(mouseHandler); } /** * Uninstall the support from the specified Diagram * * @param Diagram */ public void uninstall(Diagram diagram) { diagram.removeMouseListener(mouseHandler); diagram.removeMouseMotionListener(mouseHandler); // Clean up reset(); } /** * Called when a link has been pressed */ protected void linkPressed(PolyLink link, MouseEvent event) { } /** * Called when a link has been clicked */ protected void linkClicked(PolyLink link, MouseEvent event) { } /** * Called when a link has been pressed */ protected void linkReleased(PolyLink link, MouseEvent event) { } /** * @class MouseHandler */ protected class MouseHandler extends MouseInputAdapter { /** * Called when the mouse is pressed. * * @param MouseEvent */ public void mousePressed(MouseEvent e) { // Skip processing this event when some modifier is being used, a popup might // start or something has already consumed the event if(e.isConsumed() || e.isShiftDown() || e.isControlDown() || e.isAltDown()) return; // Get the diagram and the point diagram = (Diagram)e.getSource(); Point2D pt = e.getPoint(); Diagram diagram = (Diagram)e.getSource(); Figure figure = diagram.findFigure(pt); // Find a link if(!(figure instanceof PolyLink)) { reset(); return; } polyLink = (PolyLink)figure; // Start a drag if this is a single click, do not consume this event. This // might just be someone sloppily double clicking if(SwingUtilities.isLeftMouseButton(e)) pressPoint = pt; linkPressed(polyLink, e); } /** * Called when the mouse is clicked. * * @param MouseEvent */ public void mouseClicked(MouseEvent e) { // If the right button was used & nothing else has consumed the event // try to join two segments if(!e.isConsumed() && SwingUtilities.isRightMouseButton(e)) { Diagram diagram = (Diagram)e.getSource(); Point pt = e.getPoint(); // Find a link Figure figure = diagram.findFigure(pt); if(!(figure instanceof PolyLink)) return; PolyLink polyLink = (PolyLink)figure; DiagramUI ui = (DiagramUI)diagram.getUI(); // Make sure the place clicked was a point that can be removed int point = polyLink.pointFor(pt.getX(), pt.getY(), CLICK_TOLERANCE*2.0); if(point > 0 && point < (polyLink.getPointCount() - 1)) { e.consume(); fireToolStarted(); // Damage & refresh ui.damageFigure(polyLink); polyLink.join(point); ui.refreshFigure(polyLink); } linkClicked(polyLink, e); } } /** * Called when the dragging takes place. * * @param MouseEvent */ public void mouseDragged(MouseEvent e) { // Skip if the wrong button was used or something else has consumed the event if(e.isConsumed() || !SwingUtilities.isLeftMouseButton(e)) return; // Start a new operation if the link has been clicked and is just waiting to // be dragged. This allows the ui to handle sloppy clicks better if(pressPoint != null) { // Check to see if this drag exceed the tolerance if(pressPoint.distance(e.getPoint()) >= DRAG_TOLERANCE) { Point2D pt = pressPoint; pressPoint = null; // Find the closest segment int segment = polyLink.segmentFor(pt, CLICK_TOLERANCE); if(segment == -1) return; fireToolStarted(); // Try to use an existing point first. If nothing was close enough // split the segment and use the new point int point = polyLink.pointFor(pt.getX(), pt.getY(), CLICK_TOLERANCE*2.0); if(point > 0 && point < (polyLink.getPointCount() - 1)) dragPoint = polyLink.getPN(point); else dragPoint = polyLink.split(segment, pt); // Change the cursor on glass pane originalCursor = diagram.getCursor(); diagram.setCursor(HD_CURSOR); } } // If a drag has been started, update the point if(dragPoint != null) { e.consume(); DiagramUI ui = (DiagramUI)diagram.getUI(); // Damage & refresh ui.damageFigure(polyLink); dragPoint.setLocation(e.getPoint()); ui.refreshFigure(polyLink); } } /** * Called when the dragging to stops. * * @param MouseEvent */ public void mouseReleased(MouseEvent e) { // If there was a drag behing handled by this tool cleanup if(dragPoint != null) { e.consume(); // Force a repaint when appropriate ((DiagramUI)diagram.getUI()).refreshRegion(null); linkReleased(polyLink, e); fireToolFinished(); reset(); } // Clear the press point once the mouse is released // it may have been set, even if a drag was not started } } /* MouseHandler */ /** * Clean up */ protected void reset() { // Reset cursor if(diagram != null && originalCursor != null) diagram.setCursor(originalCursor); // Clear variables diagram = null; dragPoint = null; originalCursor = null; polyLink = null; pressPoint = null; } }